package com.school.movie.business.web.controller.front;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.school.movie.business.web.controller.BaseController;
import com.school.movie.business.web.model.pojo.City;
import com.school.movie.business.web.model.vo.*;
import com.school.movie.common.bean.ActorTypeBeanVo;
import com.school.movie.common.enums.Redirect;
import com.school.movie.common.model.BaseResponse;
import com.school.movie.common.model.ResultCode;
import com.school.movie.common.utils.*;
import com.school.movie.service.imp.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.inject.Inject;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.school.movie.common.constant.Constants.Movie.MovieAction.HAS_HOPE_LOOK;
import static com.school.movie.common.constant.Constants.User.Authorization.CERTIFY;


/**
 * 前台控制器
 *
 * @author zhaoren
 */
@Controller
@RequestMapping("/front/index")
@RequiredArgsConstructor(onConstructor_ = @Inject)
@Slf4j
public class IndexController extends BaseController {

    private final ProvinceServiceImp provinceService;
    private final CityServiceImpl cityService;
    private final MovieServiceImpl movieService;
    private final OrderServiceImpl orderService;
    private final AgentInfoServiceImpI agentService;
    private final MovieHallServiceImp hallService;
    private final UserServiceImpl userService;
    private final SysLogServiceImp logService;
    private final PlanServiceImp planService;
    private final ForumServiceImp forumService;
    private final ActorServiceImp actorService;
    @Value("${upload.absPath}")
    String absPath;

    private static final String REDIRECT = "redirect:";
    private static final String FORWARD = "forward:";

    /**
     * 展示首页需要的数据
     *
     * @param map
     * @return
     */
    @RequestMapping("/index")
    public String index(ModelMap map) {
        List<MovieVo> movieList1 = movieService.findMovieListByPlayType(1);
        List<MovieVo> movieList2 = movieService.findMovieListByPlayType(2);
        List<MovieVo> movieList3 = movieService.findMovieListByPlayType(3);
        //今日票房
        List<OrderVo> saleTop = orderService.saleTop();
        MovieVo movie = null;
        if (saleTop != null && saleTop.size() > 0) {
            movie = movieService.getById(saleTop.get(0).getMovieId());
            movie.setAreaName(saleTop.get(0).getSalePrice() + "");
            saleTop.remove(0);
        }
        //今日票房汇总
        float todayTotal = orderService.saleAll();
        //最受期待
        List<MovieVo> movieLoveList = movieService.movieLoveList(1);
        //评分排名
        MovieVo movie2 = null;
        List<MovieVo> movieForumList = movieService.movieForum(1);
        if (movieForumList != null && movieForumList.size() > 0) {
            movie2 = movieForumList.get(0);
            movieForumList.remove(0);
        }
        map.addAttribute("movieList1", movieList1);
        map.addAttribute("movieList2", movieList2);
        map.addAttribute("movieList3", movieList3);
        map.addAttribute("movie", movie);
        map.addAttribute("saleTop", saleTop);
        map.addAttribute("todayTotal", todayTotal);
        map.addAttribute("movieLoveList", movieLoveList);
        map.addAttribute("movieForumList", movieForumList);
        map.addAttribute("movie2", movie2);

        return "/front/index";
    }

    /**
     * 列出所有省
     *
     * @return
     */
    @ResponseBody
    @RequestMapping("/cityList")
    public Map<String, List<ProvinceVo>> cityList() {
        List<ProvinceVo> cityList = provinceService.list();
        Map<String, List<ProvinceVo>> map = new HashMap(CollectionUtils.getHashMapCapacity(cityList.size()));
        map.put("provList", cityList);
        return map;
    }


    /**
     * 选中一个城市
     *
     * @param cityId
     * @param request
     * @param response
     * @return
     * @throws UnsupportedEncodingException
     */
    @RequestMapping("/myCity")
    @ResponseBody
    public Map myCity(int cityId, HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
        Map map = new HashMap(2);
        CityVo city = provinceService.myCity(cityId);
        setCookie(request, response, city.getCityId(), city.getCityName());
        map.put("city", city);
        return map;
    }

    private void setCookie(HttpServletRequest request, HttpServletResponse response, int cityId, String cityName) throws UnsupportedEncodingException {
        Cookie ckCityId = new Cookie("cityId", cityId + "");
        Cookie ckCityName = new Cookie("cityName", URLEncoder.encode(cityName, "utf-8"));
        //十分钟的有效期
        ckCityId.setMaxAge(((int) TimeUnit.MINUTES.toSeconds(30)));
        ckCityName.setMaxAge(((int) TimeUnit.MINUTES.toSeconds(30)));
        ckCityId.setPath(request.getContextPath());
        ckCityName.setPath(request.getContextPath());
        response.addCookie(ckCityId);
        response.addCookie(ckCityName);
    }

    /**
     * 将自动定位的城市写入cookie
     *
     * @param cityName
     */
    @PostMapping("setCityCookie")
    @ResponseBody
    public boolean SetCityCookie(HttpServletRequest request, HttpServletResponse response, String cityName) throws UnsupportedEncodingException {
        City city = cityService.lambdaQuery().eq(City::getCityName, cityName).one();
        if (Objects.isNull(city)) {
            return false;
        }
        setCookie(request, response, city.getCityId(), cityName);
        return true;
    }

    /**
     * 电影列表
     *
     * @param playType
     * @param movieTypeId
     * @param movieYearId
     * @param movieAreaId
     * @param session
     * @param map
     * @return
     */
    @RequestMapping("/movie")
    public String movie(int playType, int movieTypeId, int movieYearId, int movieAreaId, HttpSession session, ModelMap map) {
        if (playType == 0) {
            if (session.getAttribute("playType") != null) {
                playType = (Integer) session.getAttribute("playType");
            }
        } else {
            session.setAttribute("playType", playType);
        }
        if (playType == 0) {
            playType = 2;//默认正在热映
            session.setAttribute("playType", playType);
        }
        if (movieTypeId == -1) {
            if (session.getAttribute("movieTypeId") != null) {
                movieTypeId = (Integer) session.getAttribute("movieTypeId");
            }
        } else {
            session.setAttribute("movieTypeId", movieTypeId);
        }
        if (movieTypeId == -1) {
            movieTypeId = 0;
            session.setAttribute("movieTypeId", movieTypeId);
        }
        if (movieYearId == -1) {
            if (session.getAttribute("movieYearId") != null) {
                movieYearId = (Integer) session.getAttribute("movieYearId");
            }
        } else {
            session.setAttribute("movieYearId", movieYearId);
        }
        if (movieYearId == -1) {
            movieYearId = 0;
            session.setAttribute("movieYearId", movieYearId);
        }
        if (movieAreaId == -1) {
            if (session.getAttribute("movieAreaId") != null) {
                movieAreaId = (Integer) session.getAttribute("movieAreaId");
            }
        } else {
            session.setAttribute("movieAreaId", movieAreaId);
        }
        if (movieAreaId == -1) {
            movieAreaId = 0;
            session.setAttribute("movieAreaId", movieAreaId);
        }
        MovieVo movie = new MovieVo();
        movie.setPlayType(playType);
        movie.setMovieAreaId(movieAreaId);
        movie.setMovieYearId(movieYearId);
        movie.setMovieTypeId(movieTypeId);
        List<MovieVo> movieList = movieService.movieListByCondition(movie);
        List<MovieYearVo> yearList = movieService.yearList();
        List<MovieTypeVo> typeList = movieService.movieTypeList();
        List<AreaVo> areaList = movieService.areaList();

        map.addAttribute("movieList", movieList);
        map.addAttribute("yearList", yearList);
        map.addAttribute("typeList", typeList);
        map.addAttribute("areaList", areaList);
        return "front/movie";
    }

    /**
     * 影院列表
     *
     * @param cityId
     * @param hallTypeId
     * @param session
     * @param map
     * @return
     */
    @RequestMapping("/agent")
    public String agent(
            @CookieValue(value = "cityId", defaultValue = "1") String cityId,
            int hallTypeId,
            HttpSession session,
            ModelMap map
    ) {
        if (hallTypeId == -1) {
            if (session.getAttribute("hallTypeId") != null) {
                hallTypeId = (Integer) session.getAttribute("hallTypeId");
            }
        } else {
            session.setAttribute("hallTypeId", hallTypeId);
        }
        if (hallTypeId == -1) {
            hallTypeId = 0;
            session.setAttribute("hallTypeId", hallTypeId);
        }
        List<AgentInfo> agentList = agentService.getAgentList(Integer.parseInt(cityId), hallTypeId);

        List<HallTypeVo> hallTypeList = agentService.getHallTypeList();
        map.addAttribute("agentList", agentList);
        map.addAttribute("hallTypeList", hallTypeList);
        return "front/agent";
    }

    /**
     * 影院排片列表
     *
     * @param cityId
     * @param agentId
     * @param session
     * @param map
     * @return
     */
    @RequestMapping("/agentDetail")
    public String agentDetail(@CookieValue(value = "cityId", defaultValue = "1") String cityId, int agentId, HttpSession session, ModelMap map) {
        AgentInfo agent = agentService.getAgentById(agentId);
//        List<HallTypeVo> hallTypeList = agentService.hallTypeList();
        map.addAttribute("agent", agent);
        List<AgentInfo> agentList = agentService.getAgentList(Integer.parseInt(cityId), 0);
        map.addAttribute("agentList", agentList);
        List<PlanVo> planList = agentService.getPlanDetail(agentId);
        map.addAttribute("planList", planList);
        return "front/agentInfo";
    }


    /**
     * 用户注册
     *
     * @param user
     * @param session
     * @param map
     * @param randCode
     * @return
     */
    @RequestMapping("/userAdd")
    public String userAdd(UserVo user, HttpSession session, ModelMap map, String randCode) {
        if (session.getAttribute("rand") == null) {
            return "/front/reg";
        }
        String msg = "";
        String rand = session.getAttribute("rand").toString();
        if (rand == null || randCode == null) {
            msg = "验证码错误";
            map.addAttribute("msg", msg);
            return "/front/reg";
        }
        rand = rand.toUpperCase();
        randCode = randCode.toUpperCase();
        if (!rand.equals(randCode)) {
            msg = "验证码错误";
            map.addAttribute("msg", msg);
            return "/front/reg";
        }
        UserVo u = userService.getById(user.getMobile());
        if (u != null) {
            map.addAttribute("msg", "用户已经存在");
            return "/front/reg";
        } else {
            user.setState(1);
            user.setSex("男");
            user.setHeadImg("card/headImg.png");
            user.setState(1);
            userService.add(user);
            logService.add(BaseConstants.LOG_ADD, user.toString());
        }
        session.setAttribute("member", user);
        return "front/myInfo";
    }


    /**
     * 修改用户
     *
     * @param user
     * @param session
     * @return
     */
    @RequestMapping(CERTIFY + "/userReg")
    public String updateUser(UserVo user, HttpSession session) {
        UserVo u = userService.getById(user.getMobile());
        if (u != null) {
            user.setHeadImg(u.getHeadImg());
            user.setState(u.getState());
            userService.update(user);
            logService.add(BaseConstants.LOG_UPDATE, user.toString());
        }
        session.setAttribute("member", user);
        return "front/myInfo";
    }


    /**
     * 上传头像
     *
     * @param user
     * @param file1
     * @param session
     * @return
     * @throws Exception
     */
    @RequestMapping(CERTIFY + "/uploadHead")
    public String uploadHead(UserVo user, MultipartFile file1, HttpSession session) throws IOException {
        UserVo u = userService.getById(user.getMobile());
        if (u != null) {
            String picName = UUID.randomUUID().toString();
            // 截取文件的扩展名(如.jpg)
            String oriName = file1.getOriginalFilename();
            System.out.println("--上传文件名-->>" + oriName);
            String extName = oriName.substring(oriName.lastIndexOf("."));
            String newFileName = picName + extName;
            File targetFile = new File(absPath, newFileName);
            // 保存文件
            file1.transferTo(targetFile);
            u.setHeadImg("card/" + newFileName);
            userService.update(u);
            logService.add(BaseConstants.LOG_UPDATE, u.toString());
        }
        session.setAttribute("member", u);
        return "/front/myInfo";
    }


    /**
     * 我的信息
     *
     * @param session
     * @return
     * @throws Exception
     */
    @RequestMapping(CERTIFY + "/myInfo")
    public String myInfo(HttpSession session) {
        return "front/myInfo";
    }


    /**
     * 退出登录
     *
     * @param session
     * @return
     * @throws Exception
     */
    @RequestMapping("/exit")
    public String exit(HttpSession session) {
        session.invalidate();
        return REDIRECT + "/front/index/index";
    }


    /**
     * 用户登录
     *
     * @param user
     * @param map
     * @param session
     * @return
     */
    @PostMapping("/login")
    public String login(UserVo user, ModelMap map, HttpSession session, String redirect) {
        UserVo u = userService.getById(user.getMobile());
        if (u == null || !u.getPassword().equals(MD5Utils.md5(user.getPassword()))) {
            map.addAttribute("msg", "用户名或密码错误!");
            return "/front/login";
        }
        if (u.getState() == 0) {
            map.addAttribute("msg", "用户已禁止登录");
            return "/front/login";
        }

        session.setAttribute("member", u);

        //重定向url不为null,重定向到指定页面
        if (StringUtils.isNotEmpty(redirect)) {
            int startIndex = redirect.lastIndexOf("/");
            int endIndex = redirect.lastIndexOf("?");
            String pathTail = "";
            if (endIndex != -1) {
                pathTail = redirect.substring(startIndex + 1, endIndex);
            } else {
                pathTail = redirect.substring(startIndex + 1);
            }
            if (pathTail.equals(Redirect.FORUM_TO_MOVIE_DETAIL.name())) {
                //评论时没有登陆，跳转登陆成功后重新跳转到电影详情页面
                String movieId = redirect.substring(endIndex + 1);
                return REDIRECT + "movieDetail?" + movieId;
            } else if (pathTail.equals(Redirect.PAY_TO_SEAT.name())) {
                String planId = redirect.substring(endIndex + 1);
                return REDIRECT + "seat?" + planId;
            }
            return REDIRECT + redirect.substring(6);
        }

        return REDIRECT + "/front/index/index";
    }


    /**
     * 影院选座
     *
     * @param cityId
     * @param planId
     * @param map
     * @return
     */
    @RequestMapping("/seat")
    public String seat(@CookieValue(value = "cityId", defaultValue = "1") String cityId, int planId, ModelMap map) {
        PlanVo plan = agentService.getPlanById(planId);
        map.addAttribute("plan", plan);
        MovieVo movie = movieService.getById(plan.getMovieId());
        map.addAttribute("movie", movie);
        List<AgentInfo> agentList = agentService.getAgentList(Integer.parseInt(cityId), 0);
        map.addAttribute("agentList", agentList);
        List<HallSeatVo> seatList = orderService.findSeatBuyList(plan.getHallId(), plan.getPlanId());
        map.addAttribute("seatList", seatList);
        MovieHallVo hall = hallService.getById(plan.getHallId());
        map.addAttribute("hall", hall);
        return "front/hallInfo";
    }

    /**
     * 我的订单
     *
     * @param session
     * @param map
     * @return
     */
    @RequestMapping(CERTIFY + "/myOrder")
    public String myOrder(HttpSession session, ModelMap map) {
        UserVo user = getMember(session);
        List<OrderVo> myOrderList = orderService.getMyOrder(user.getMobile());
        map.addAttribute("myOrderList", myOrderList);
        return "front/member";
    }


    /**
     * 添加订单
     *
     * @param session
     * @param planId
     * @param seatIds
     * @param payType
     * @param map
     * @return
     */
    @RequestMapping(CERTIFY + "/addOrder")
    public String addOrder(HttpSession session, int planId, String seatIds, String payType, ModelMap map) {
        //TODO 添加电影票的过程中有可能别人的正在购买该电影票，因此需要判定一下并发的情况
        UserVo user = getMember(session);
        PlanVo plan = planService.getById(planId);
        String[] arr = seatIds.split(",");
        if (arr.length > 0) {
            long orderId = SnowflakeIdWorker.getNextId();
            for (String s : arr) {
                insertNewOrder(orderService, logService, planId, payType, user, plan, s, orderId);
            }
        }
        List<OrderVo> myOrderList = orderService.getMyOrder(user.getMobile());
        map.addAttribute("myOrderList", myOrderList);

        //需要重定向到购买之后的订单页面，否则就会出现重复购票的现象
        return REDIRECT + "/front/index/v/myOrder";
    }


    /**
     * 电影明细
     *
     * @param movieId
     * @param map
     * @return
     */
    @RequestMapping("/movieDetail")
    public String movieDetail(
            @RequestParam(value = "movieId", defaultValue = "-1", required = false) Integer movieId,
            ModelMap map,
            HttpServletRequest req,
            HttpSession session
    ) {
        if (movieId == -1) {
            movieId = Integer.valueOf(req.getParameter("mid"));
        }

        MovieVo movie = movieService.getMovieDetailById(movieId);
        List<MovieActorVo> actorList = movieService.getMovieActorList(movieId);

        List<ActorTypeBeanVo> actorTypeBeanVos = new ArrayList<>();
        actorList2ActorTypeList(actorList, actorTypeBeanVos);

        initHopeLook(movieId, map, session);

        List<MovieVo> movieList = movieService.findMovieListByPlayType(2);
        map.addAttribute("movie", movie);
        map.addAttribute("actorList", actorTypeBeanVos);
        map.addAttribute("movieList", movieList);

        return "front/movieDetail";
    }

    private void initHopeLook(Integer movieId, ModelMap map, HttpSession session) {
        UserVo user = getMember(session);
        if (Objects.nonNull(user)) {
            if (userService.findHopeLookMovies(movieId, user.getMobile()).isEmpty()) {
                map.addAttribute(HAS_HOPE_LOOK.getName(), false);
            } else {
                map.addAttribute(HAS_HOPE_LOOK.getName(), true);
            }
        } else {
            map.addAttribute(HAS_HOPE_LOOK.getName(), false);
        }
    }


    /**
     * 评论分页查询
     *
     * @param movieId
     * @param page
     * @param size
     * @return
     */
    @GetMapping("pageForumList")
    @ResponseBody
    public BaseResponse<List<ForumVo>> pageForumList(
            @RequestParam(value = "movieId", defaultValue = "-1", required = false) Integer movieId,
            @RequestParam(defaultValue = "1", required = false) int page,
            @RequestParam(defaultValue = "10", required = false) int size,
            HttpSession session
    ) {
        PageHelper.startPage(page, size);
        List<ForumVo> forumList = movieService.getForumList(movieId);
        //用户已经登陆
        UserVo user = getMember(session);
        if (Objects.nonNull(user)) {
            //判断用户是否点赞评论逻辑
            for (ForumVo forumVo : forumList) {
                Set<Integer> approveForums = userService.getApproveForum(user.getMobile(), forumVo.getForumId());
                if (approveForums.isEmpty()) {
                    //该用户未点赞该评论
                    forumVo.setHasApprove(false);
                } else {
                    forumVo.setHasApprove(true);
                }
            }
        } else {
            for (ForumVo forumVo : forumList) {
                forumVo.setHasApprove(false);
            }
        }

        PageInfo<ForumVo> pageInfo = new PageInfo<>(forumList);
        return BaseResponse
                .<List<ForumVo>>builder()
                .data(pageInfo.getList())
                .code(ResultCode.SUCCESS.getCode())
                .recordsTotal(pageInfo.getTotal())
                .message("评论查询成功!")
                .build();
    }

    /**
     * 写评论
     *
     * @param forum
     * @return
     */
    @RequestMapping(CERTIFY + "/forum")
    public String addForum(ForumVo forum, RedirectAttributes redirectAttributes) {
        forumService.add(forum);
        redirectAttributes.addAttribute("mid", forum.getMovieId());
        //需要重定向到电影详情页面，页面刷新之后重复评论
        return REDIRECT + "/front/index/movieDetail";
    }


    /**
     * 增加想看数量
     *
     * @param movieId
     * @param mobile  用户手机号
     * @return
     */
    @RequestMapping(CERTIFY + "/hopeLook")
    @ResponseBody
    public Map<String, Object> hopeLook(
            @RequestParam(name = "movieId") int movieId,
            @RequestParam(name = "mobile") String mobile
    ) {
        Map<String, Object> map = new HashMap(4);
        Set<Integer> hopeLookMovies = userService.findHopeLookMovies(movieId, mobile);
        boolean hasHopeLook = true;
        if (hopeLookMovies.isEmpty()) {
            movieService.incHopeLook(movieId);
            userService.addHopeLookMovie(movieId, mobile);
        } else {
            //取消收藏
            hasHopeLook = false;
            userService.cancelHopeLookMovie(movieId, mobile);
            movieService.decHopeLook(movieId);
        }
        MovieVo movie = movieService.getById(movieId);

        map.put("hopeLook", movie.getHopeLook());
        map.put("isHasHopeLookBefore", hasHopeLook);
        return map;
    }


    /**
     * 榜单
     *
     * @param map
     * @return
     */
    @RequestMapping("/movieTop")
    public String movieTop(ModelMap map) {
        MovieVo movie = null;
        List<MovieVo> movieForumList = movieService.movieForum(0);
        for (MovieVo m : movieForumList) {
            List<ActorVo> actorList = movieService.majorActor(m.getMovieId());
            String str = "";
            for (ActorVo act : actorList) {
                str += act.getActorName() + ",";
            }
            if (str.length() > 0) {
                str = str.substring(0, str.length() - 1);
            }
            m.setAreaName(str);
        }
        if (movieForumList != null && movieForumList.size() > 0) {
            movie = movieForumList.get(0);
            movieForumList.remove(0);
        }
        movie.setContent(ContextUtils.dateToShortStr(new Date()));
        map.addAttribute("movie", movie);
        map.addAttribute("movieForumList", movieForumList);
        return "front/movieTop";
    }

    /**
     * 演员列表
     *
     * @param map
     * @return
     */
    @RequestMapping("/actor")
    public String actor(ModelMap map) {
        List<ActorVo> actorList = actorService.list(null);
        map.addAttribute("actorList", actorList);
        return "front/actor";
    }

    /**
     * 搜索电影
     */
    @RequestMapping("/searchMovie")
    public String searchMovie(String movieName, ModelMap map) {
        List<MovieVo> movieList = movieService.movieListByName(movieName);
        map.addAttribute("movieList", movieList);

        List<MovieYearVo> yearList = movieService.yearList();
        List<MovieTypeVo> typeList = movieService.movieTypeList();
        List<AreaVo> areaList = movieService.areaList();

        map.addAttribute("movieList", movieList);
        map.addAttribute("yearList", yearList);
        map.addAttribute("typeList", typeList);
        map.addAttribute("areaList", areaList);
        return "front/movie";
    }

    /**
     * 用户点赞评论
     *
     * @param forumId
     * @param mobile
     * @return
     */
    @GetMapping(CERTIFY + "/approve")
    @ResponseBody
    public BaseResponse<Map<String, Object>> approve(
            @RequestParam(name = "forumId") int forumId,
            @RequestParam(name = "mobile") String mobile
    ) {
        Map<String, Object> data = new HashMap<>(4);
        Set<Integer> approveForums = userService.getApproveForum(mobile, forumId);
        boolean hasApprove = true;
        if (approveForums.isEmpty()) {
            userService.approve(forumId, mobile);
            movieService.incForumApproves(forumId);
        } else {
            hasApprove = false;
            userService.cancelApprove(forumId, mobile);
            movieService.decForumApproves(forumId);
        }
        long countNumber = movieService.getForumApproves(forumId);
        data.put("countNumber", countNumber);
        data.put("hasApprove", hasApprove);
        return BaseResponse
                .<Map<String, Object>>builder()
                .data(data)
                .build();
    }

}
